package com.hilin.hilinim.netty.ws;

import com.hilin.common.common.ReturnCode;
import com.hilin.common.util.EntityUtils;
import com.hilin.entity.po.AccountInfoPo;
import com.hilin.entity.po.MsgInfoPo;
import com.hilin.entity.vo.RespVo;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

@Slf4j
@ChannelHandler.Sharable
@Component
public class WsHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    private final IWsHandler iWsHandler;

    public WsHandler(@Autowired(required = false) IWsHandler iWsHandler) {
        this.iWsHandler = iWsHandler == null ? new DefaultWsHandler() : iWsHandler;
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        //添加到channelGroup 通道组
        WsUtils.remove(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //首次连接是FullHttpRequest，处理参数 by zhengkai.blog.csdn.net
        if (msg instanceof FullHttpRequest) {
            try {
                FullHttpRequest request = (FullHttpRequest) msg;
                // 如果指定回调，则根据回调判断是否连接成功
                AccountInfoPo user = iWsHandler.handshake(request, ctx.channel());
                if (ObjectUtils.isEmpty(user)
                        || ObjectUtils.isEmpty(user.getOrgId())
                        || ObjectUtils.isEmpty(user.getAccountId())) {
                    log.info("用户认证失败");
                    WsUtils.setUserAuthResult(ctx.channel(), ReturnCode.AUTH_ERROR.resp());
                } else {
                    WsUtils.setUserAuthResult(ctx.channel(), ReturnCode.SUCCESS.resp());
                }
                WsUtils.add(ctx.channel(), user.getOrgId(), user.getAccountId());
                if (request.uri().indexOf("?") > 0) {
                    String newUri = request.uri().substring(0, request.uri().indexOf("?"));
                    request.setUri(newUri);
                }

            } catch (Exception e) {
                log.error("[WS连接]执行错误", e);
                ctx.channel().disconnect();
                return;
            }
        }
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        RespVo<Object> result = WsUtils.getUserAuthResult(ctx.channel());
        if (ObjectUtils.isEmpty(result)) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame(
                    EntityUtils.toJsonString(MsgInfoPo.builder().content("用户认证失败").build())));
            ctx.close();
        } else if (result.getCode() != RespVo.CODE_SUCCESS) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame(
                    EntityUtils.toJsonString(result)));
            ctx.close();
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame webSocketFrame) {
        try {
            WsUtils.setMsgLastTime(ctx.channel(), System.currentTimeMillis());
            AccountInfoPo userInfo = AccountInfoPo.builder()
                    .accountId(WsUtils.getAccountId(ctx.channel()))
                    .orgId(WsUtils.getOrgId(ctx.channel()))
                    .build();
            iWsHandler.onMsg(userInfo, ctx.channel());
            if (webSocketFrame instanceof TextWebSocketFrame) {
                // 正常的TEXT消息类型
                String msg = ((TextWebSocketFrame) webSocketFrame).text();
                if (log.isDebugEnabled()) {
                    log.debug("[WS消息]收到文本数据 {} msg:{}", EntityUtils.toJsonString(userInfo), msg);
                }
                String returnMsg = iWsHandler.onMsg(userInfo, msg, ctx.channel());
                if (!ObjectUtils.isEmpty(returnMsg)) {
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(returnMsg));
                }
            } else if (webSocketFrame instanceof PingWebSocketFrame) {
                // 收到客户端发送的心跳，反馈Pong帧
                if (log.isDebugEnabled()) {
                    log.debug("[WS消息]收到客户端Ping信息 {}", EntityUtils.toJsonString(userInfo));
                }
                ctx.channel().writeAndFlush(new PongWebSocketFrame());
            } else if (webSocketFrame instanceof PongWebSocketFrame) {
                // todo 收到心跳反馈消息，后续添加处理 现暂时没有需要处理的东西
                if (log.isDebugEnabled()) {
                    log.debug("[WS消息]收到客户端Pong信息,{}", EntityUtils.toJsonString(userInfo));
                }
            } else if (webSocketFrame instanceof BinaryWebSocketFrame) {
                // 二进制消息消息类型
                if (log.isDebugEnabled()) {
                    log.debug("[WS消息]收到二进制数据 {}", EntityUtils.toJsonString(userInfo));
                }
                ByteBuf msg = webSocketFrame.content();
                ByteBuf returnMsg = iWsHandler.onMsg(userInfo, msg, ctx.channel());
                if (!ObjectUtils.isEmpty(returnMsg)) {
                    ctx.channel().writeAndFlush(new BinaryWebSocketFrame(returnMsg));
                }
            } else if (webSocketFrame instanceof CloseWebSocketFrame) {
                // 二进制消息消息类型
                if (log.isDebugEnabled()) {
                    log.debug("[WS消息]用户主动退出 {}", EntityUtils.toJsonString(userInfo));
                }
                ctx.channel().close();
            }
        } catch (Exception e) {
            log.error("消息处理异常", e);
        }
    }
}
